﻿using OpenCvSharp;
using OpenCvSharp.Extensions;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using System.Windows.Forms;
using System.Xml.Linq;

namespace WindowsFormsApp1
{
    /// <summary>
    /// https://blog.csdn.net/weixin_41049188/category_8972370.html?orderBy=1
    /// https://blog.csdn.net/weixin_45590420/category_12832672.html
    /// </summary>
    public partial class mainForm : Form
    {
        public mainForm()
        {
            InitializeComponent();
        }

        private void gray_btn_Click(object sender, EventArgs e)
        {
            var mat = BitmapConverter.ToMat(pictureBox1.Image as Bitmap);
            Mat gray = new Mat();
            Cv2.CvtColor(mat, gray, ColorConversionCodes.BGR2GRAY);//转灰度图
            Cv2.ImShow("灰度图像", gray);
        }

        private void loadBtn_Click(object sender, EventArgs e)
        {
            using (OpenFileDialog openFileDialog = new OpenFileDialog())
            {
                openFileDialog.Filter = "图像文件|*.jpg;*.jpeg;*.png;*.bmp;*.tiff|所有文件|*.*";
                openFileDialog.Title = "选择要打开的图片";

                if (openFileDialog.ShowDialog() == DialogResult.OK)
                {
                    try
                    {
                        byte[] imageBytes = File.ReadAllBytes(openFileDialog.FileName);
                        var originalImage = Cv2.ImDecode(imageBytes, ImreadModes.Color);

                        // 使用OpenCV读取图片
                        //var originalImage = Cv2.ImRead(openFileDialog.FileName, ImreadModes.Color);

                        if (originalImage.Empty())
                        {
                            MessageBox.Show("无法读取图片文件！", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                            return;
                        }

                        // 克隆原始图片用于处理
                        var processedImage = originalImage.Clone();

                        // 显示图片
                        DisplayImage(processedImage);
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show($"读取图片时出错: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    }
                }
            }
        }

        private void DisplayImage(Mat image)
        {
            if (image.Empty()) return;

            try
            {
                // 调整图片大小以适应PictureBox
                Mat resizedImage = ResizeImageToFit(image, pictureBox1.Width, pictureBox1.Height);

                // 将Mat转换为Bitmap并显示
                Bitmap bitmap = BitmapConverter.ToBitmap(resizedImage);
                pictureBox1.Image?.Dispose(); // 释放之前的图片
                pictureBox1.Image = bitmap;

                resizedImage.Release();
            }
            catch (Exception ex)
            {
                MessageBox.Show($"显示图片时出错: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private Mat ResizeImageToFit(Mat image, int maxWidth, int maxHeight)
        {
            double scale = Math.Min((double)maxWidth / image.Width, (double)maxHeight / image.Height);

            if (scale < 1.0) // 需要缩小
            {
                OpenCvSharp.Size newSize = new OpenCvSharp.Size((int)(image.Width * scale), (int)(image.Height * scale));
                Mat resized = new Mat();
                Cv2.Resize(image, resized, newSize);
                return resized;
            }
            return image.Clone(); // 不需要调整大小
        }

        private void filterBtn_Click(object sender, EventArgs e)
        {
            var mat = BitmapConverter.ToMat(pictureBox1.Image as Bitmap);
            Mat blur = new Mat();
            Cv2.Blur(mat, blur, new OpenCvSharp.Size(11, 11), new OpenCvSharp.Point(-1, -1)); //注意：size 参数一定要是奇数 (均值模糊)
            Cv2.ImShow("均值滤波", blur);

            Mat gauss = new Mat();
            Cv2.GaussianBlur(mat, gauss, new OpenCvSharp.Size(11, 11), 11, 11);
            Cv2.ImShow("高斯滤波", gauss);

            Mat dst = new Mat();
            Cv2.MedianBlur(mat, dst, 5); // 使用5x5的中值滤波器
            Cv2.ImShow("中值滤波", dst);

            Mat bilateral = new Mat();
            Cv2.BilateralFilter(mat, bilateral, 9, 75, 75);  // 使用直径为9，颜色标准差和空间标准差均为75的双边滤波器
            //Cv2.ImShow("双边滤波", bilateral);
            new Window("双边滤波", bilateral, WindowFlags.AutoSize);
        }

        private void roiBtn_Click(object sender, EventArgs e)
        {
            var mat = BitmapConverter.ToMat(pictureBox1.Image as Bitmap);
            var rect = Cv2.SelectROI("选择ROI", mat);
            if (rect.Width > 0 && rect.Height > 0)
            {
                Mat roi = new Mat(mat, rect);
                Cv2.ImShow("选定的ROI", roi);
                Cv2.WaitKey(0);
                Cv2.DestroyAllWindows();
            }
        }

        private void cannyEdgeDetectionBtn_Click(object sender, EventArgs e)
        {
            string outputName = "Canny Result";
            var mat = BitmapConverter.ToMat(pictureBox1.Image as Bitmap);
            Mat gray = new Mat();

            var dst = new Mat(mat.Size(), mat.Type());

            new Window("SRC", mat, WindowFlags.AutoSize);

            mat.CopyTo(dst);

            Cv2.CvtColor(dst, gray, ColorConversionCodes.RGB2GRAY); //转为灰度图（必须转）
            new Window(outputName, WindowFlags.AutoSize);
            Cv2.Blur(gray, gray, new OpenCvSharp.Size(3, 3), new OpenCvSharp.Point(-1, -1), BorderTypes.Default);//模糊处理（降低噪点）

            GCHandle handle = GCHandle.Alloc(gray, GCHandleType.Normal);
            IntPtr userData = GCHandle.ToIntPtr(handle);
            int minVal = 50;
            int maxVal = 255;
            Cv2.CreateTrackbar("Bar :", outputName, ref minVal, maxVal, (pos, data) =>
            {
                GCHandle sHandle = GCHandle.FromIntPtr(data);
                Mat m = (Mat)sHandle.Target;

                Mat output = new Mat();
                Cv2.Canny(m, output, pos, pos * 2, 3, true);
                dst = new Mat(mat.Size(), mat.Type());
                mat.CopyTo(dst, output); 

                Cv2.ImShow(outputName, dst);
            }, userData);

            Cv2.WaitKey(0);
        }
    }
}
